package com.anlogic.sdk.programflash.ui;

import java.io.File;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import com.anlogic.sdk.programflash.ProgramFlashModel;
import com.anlogic.sdk.toolpreference.utils.FlashPreferencesUtils;
import com.anlogic.sdk.utils.options.ChipType;
import com.anlogic.sdk.openocd.ui.TargetSelectionWidget;

public class ProgramFlashDialog extends TitleAreaDialog {
	Combo chipCombo;
	Text imageFileText;
	Button imageBrowseButton;
	Text offsetText;
	Combo flashTypeCombo;

	TargetSelectionWidget targetWidget;
	
	Button useCustomizeFlash;
	Composite customizeCompsite;
	Text bankId;
	Text readCmd;
	Text pprogCmd;
	Text eraseCmd;
	Text pageSize;
	Text sectorSize;
	Text chipSize;

	Button enablePjtagButton;
	Button eraseFlashButton;
	Button enableXipButton;
	Button verifyButton;

	String[] chipTypes = ChipType.getNames();
	String[] flashTypes = new String[] { "qspi-x1-single", "qspi-x4-single", "qspi-x1-dual_stacked",
			"qspi-x4-dual_stacked", "nand", "emmc0", "emmc1" };
	String[] imageFileFilters = new String[] { "*.bin; *.mcs;*.dtb;*.fat;*.scr;*.lz4", "*.*" };

	private ProgramFlashModel model;
	
	public ProgramFlashDialog(Shell parentShell) {
		super(parentShell);
		setShellStyle(getShellStyle() | SWT.RESIZE);
		
		if (this.model == null) {
			this.model = new ProgramFlashModel();
		}
	}

	protected Control createButtonBar(Composite parent) {
		Control c = super.createButtonBar(parent);
		renameOKButton();
		validate();
		return c;
	}

	private void renameOKButton() {
		Button okButton = getButton(IDialogConstants.OK_ID);
		if (okButton != null) {
			okButton.setText("Program");
			setButtonLayoutData(okButton);
		}
	}

	private void enableOkButton(boolean flag) {
		Button button = getButton(IDialogConstants.OK_ID);
		if (button != null)
			button.setEnabled(flag);
	}

	protected Control createDialogArea(Composite parent) {
		setTitle("Program Flash Memory");
		setMessage("Program Flash Memory via Programmer.");

		Composite container = new Composite(parent, SWT.DEFER);
		container.setLayout(new GridLayout(3, false));
		container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		Label chipLabel = new Label(container, SWT.NULL);
		chipLabel.setText("Chip:");
		chipCombo = new Combo(container, SWT.POP_UP);
		GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo((Control) chipCombo);
		chipCombo.setItems(chipTypes);
		chipCombo.setData("chipCombo");
		chipCombo.select(0);
		
		targetWidget = new TargetSelectionWidget(container);
		GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(targetWidget.getContainer());
		
		Label imageFileLabel = new Label(container, SWT.NULL);
		imageFileLabel.setText("Image File:");
		imageFileText = new Text(container, SWT.BORDER);
		GridDataFactory.fillDefaults().grab(true, false).applyTo((Control) imageFileText);
		imageFileText.setData("imageFileText");
		imageBrowseButton = new Button(container, SWT.PUSH);
		imageBrowseButton.setText("Browse");
		Label offsetLabel = new Label(container, SWT.NONE);
		offsetLabel.setText("Offset:");
		offsetText = new Text(container, SWT.BORDER);
		GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo((Control) offsetText);
		offsetText.setData("offsetText");
		Label flashTypeLabel = new Label(container, SWT.NONE);
		flashTypeLabel.setText("Flash Type:");
		flashTypeCombo = new Combo(container, SWT.POP_UP);
		flashTypeCombo.setItems(flashTypes);
		flashTypeCombo.setData("flashTypeCombo");
		GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo((Control) flashTypeCombo);
		useCustomizeFlash = new Button(container, SWT.CHECK);
		useCustomizeFlash.setText("Use Customize Flash");
		useCustomizeFlash.setData("useCustomizeFlash");
		GridDataFactory.swtDefaults().span(3, 1).applyTo((Control) useCustomizeFlash);

		customizeCompsite = new Composite(parent, SWT.DEFER);
		customizeCompsite.setLayout(new GridLayout(6, false));
		customizeCompsite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		Label bankIdLabel = new Label(customizeCompsite, SWT.NONE);
		bankIdLabel.setText("bankId:");
		bankId = new Text(customizeCompsite, SWT.BORDER);
		GridData textgridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
		textgridData.widthHint = 10;
		bankId.setLayoutData(textgridData);
		Label readCmddLabel = new Label(customizeCompsite, SWT.NONE);
		readCmddLabel.setText("readCmd:");
		readCmd = new Text(customizeCompsite, SWT.BORDER);
		readCmd.setLayoutData(textgridData);
		Label pprogCmdLabel = new Label(customizeCompsite, SWT.NONE);
		pprogCmdLabel.setText("pprogCmd:");
		pprogCmd = new Text(customizeCompsite, SWT.BORDER);
		pprogCmd.setLayoutData(textgridData);
		Label eraseCmdLabel = new Label(customizeCompsite, SWT.NONE);
		eraseCmdLabel.setText("eraseCmd:");
		eraseCmd = new Text(customizeCompsite, SWT.BORDER);
		eraseCmd.setLayoutData(textgridData);
		Label pageSizeLabel = new Label(customizeCompsite, SWT.NONE);
		pageSizeLabel.setText("pageSize:");
		pageSize = new Text(customizeCompsite, SWT.BORDER);
		pageSize.setLayoutData(textgridData);
		Label sectorSizeLabel = new Label(customizeCompsite, SWT.NONE);
		sectorSizeLabel.setText("sectorSize:");
		sectorSize = new Text(customizeCompsite, SWT.BORDER);
		sectorSize.setLayoutData(textgridData);
		Label chipSizeLabel = new Label(customizeCompsite, SWT.NONE);
		chipSizeLabel.setText("chipSize:");
		chipSize = new Text(customizeCompsite, SWT.BORDER);
		chipSize.setLayoutData(textgridData);
		
		Composite option = new Composite(parent, SWT.DEFER);
		option.setLayout(new GridLayout(3, false));
		option.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		enablePjtagButton = new Button(option, SWT.CHECK);
		enablePjtagButton.setText("Use Pjtag");
		GridDataFactory.swtDefaults().span(3, 1).applyTo((Control) enablePjtagButton);
		enableXipButton = new Button(option, SWT.CHECK);
		enableXipButton.setText("Enable XIP Mode");
		GridDataFactory.swtDefaults().span(3, 1).applyTo((Control) enableXipButton);
		eraseFlashButton = new Button(option, SWT.CHECK);
		eraseFlashButton.setText("Erase the whole flash");
		GridDataFactory.swtDefaults().span(3, 1).applyTo((Control) eraseFlashButton);
		verifyButton = new Button(option, SWT.CHECK);
		verifyButton.setText("Verify after flash");
		GridDataFactory.swtDefaults().span(3, 1).applyTo((Control) verifyButton);
		loadPreferences();
		addListeners();
		return (Control) parent;
	}

	private void loadPreferences() {
		IEclipsePreferences flashPrefs = FlashPreferencesUtils.getPreferences();
		int chipComboIndex = flashPrefs.getInt("chipCombo", 0);
		chipCombo.select(chipComboIndex);

		String image = flashPrefs.get("imageFileText", "");
		imageFileText.setText(image);

		String offsetContent = flashPrefs.get("offsetText", "");
		offsetText.setText(offsetContent);
		int flashTypeIndex = flashPrefs.getInt("flashTypeCombo", 0);
		flashTypeCombo.select(flashTypeIndex);
		boolean isUseCustomize = flashPrefs.getBoolean("useCustomizeFlash", false);
		useCustomizeFlash.setSelection(isUseCustomize);
		if (flashTypeCombo.getText().contains("qspi")) {
			useCustomizeFlash.setEnabled(true);
		} else {
			useCustomizeFlash.setEnabled(false);
		}
		if (useCustomizeFlash.getEnabled() && useCustomizeFlash.getSelection()) {
			setCustomComposite(true);
		} else {
			setCustomComposite(false);
		}
		String bankIdStr = flashPrefs.get("bankId", "");
		bankId.setData("bankId");
		bankId.setText(bankIdStr);
		String readCmdStr = flashPrefs.get("readCmd", "");
		readCmd.setData("readCmd");
		readCmd.setText(readCmdStr);
		String pprogCmdStr = flashPrefs.get("pprogCmd", "");
		pprogCmd.setData("pprogCmd");
		pprogCmd.setText(pprogCmdStr);
		String eraseCmdStr = flashPrefs.get("eraseCmd", "");
		eraseCmd.setData("eraseCmd");
		eraseCmd.setText(eraseCmdStr);
		String pageSizeStr = flashPrefs.get("pageSize", "");
		pageSize.setData("pageSize");
		pageSize.setText(pageSizeStr);

		String sectorSizeStr = flashPrefs.get("sectorSize", "");
		sectorSize.setData("sectorSize");
		sectorSize.setText(sectorSizeStr);

		String chipSizeStr = flashPrefs.get("chipSize", "");
		chipSize.setData("chipSize");
		chipSize.setText(chipSizeStr);

		boolean enablePjtag = flashPrefs.getBoolean("enablePjtagButton", false);
		enablePjtagButton.setData("enablePjtagButton");
		enablePjtagButton.setSelection(enablePjtag);
		
		boolean eraseFlash = flashPrefs.getBoolean("eraseFlashButton", false);
		eraseFlashButton.setData("eraseFlashButton");
		eraseFlashButton.setSelection(eraseFlash);

		boolean enableXip = flashPrefs.getBoolean("enableXipButton", false);
		enableXipButton.setData("enableXipButton");
		enableXipButton.setSelection(enableXip);

		boolean isVerify = flashPrefs.getBoolean("verifyButton", false);
		verifyButton.setData("verifyButton");
		verifyButton.setSelection(isVerify);

	}

	private void setCustomComposite(boolean enable) {
		for (Control c : customizeCompsite.getChildren()) {
			c.setEnabled(enable);
		}
	}

	private void addListeners() {
		imageFileText.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});

		imageBrowseButton.addSelectionListener((SelectionListener) new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
				dialog.setFilterExtensions(imageFileFilters);
				String result = dialog.open();
				if (result != null) {
					imageFileText.setText(result);
					validate();
				}
			}
		});

		flashTypeCombo.addSelectionListener((SelectionListener) new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (flashTypeCombo.getText().contains("qspi")) {
					useCustomizeFlash.setEnabled(true);
				} else {
					useCustomizeFlash.setEnabled(false);
				}
				if (useCustomizeFlash.getEnabled() && useCustomizeFlash.getSelection()) {
					setCustomComposite(true);
				} else {
					setCustomComposite(false);
				}
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});

		useCustomizeFlash.addSelectionListener((SelectionListener) new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				setCustomComposite(useCustomizeFlash.getSelection());
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});

		bankId.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});

		readCmd.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});

		pprogCmd.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});

		eraseCmd.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});

		pageSize.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});

		sectorSize.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);

			}
		});

		chipSize.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});
		chipCombo.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});
		offsetText.addModifyListener(new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});
		enablePjtagButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);

			}
		});
		eraseFlashButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);

			}
		});
		enableXipButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});
		verifyButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				validate();
				FlashPreferencesUtils.savePreferences(e);
			}
		});
	}

	private void validate() {
		String image = imageFileText.getText();
		File file = new File(image);

		if (!file.isFile() || !file.exists()) {
			if (eraseFlashButton.getSelection() && flashTypeCombo.getText().contains("emmc")) {
				setErrorMessage("Cannot erase emmc flash without image file!");
				enableOkButton(false);
				return;
			}
			
			if (!eraseFlashButton.getSelection() && !enableXipButton.getSelection()) {
				setErrorMessage("Specified file does not exits");
				enableOkButton(false);
				return;
			}
		}
		
		if (!offsetText.getText().trim().isEmpty()) {
			if (checkForValidNumber(offsetText.getText().trim()) == -1L) {
				setErrorMessage("Offset is illegal!");
				enableOkButton(false);
				return;
			}
		}
		
		if (useCustomizeFlash.getEnabled() && useCustomizeFlash.getSelection()) {
			if (!checkHexText(bankId.getText().trim(), "blankId"))
				return;
			
			if (!checkHexText(readCmd.getText().trim(), "readCmd"))
				return;
			
			if (!checkHexText(pprogCmd.getText().trim(), "pprogCmd"))
				return;
			
			if (!checkHexText(eraseCmd.getText().trim(), "eraseCmd"))
				return;
			
			if (!checkHexText(pageSize.getText().trim(), "pageSize"))
				return;
			
			if (!checkHexText(sectorSize.getText().trim(), "sectorSize"))
				return;
			
			if (!checkHexText(chipSize.getText().trim(), "chipSize"))
				return;
		}

		setErrorMessage(null);
		enableOkButton(true);
	}

	private boolean checkHexText(String text, String name) {
		if (text.isEmpty()) {
			setErrorMessage(name + " is empty!");
			enableOkButton(false);
			return false;
		}
		if (checkForValidNumber(text) == -1L) {
			setErrorMessage(name + " is illegal!");
			enableOkButton(false);
			return false;
		}
		return true;
	}
	
	private long checkForValidNumber(String str) {
		if (str == null || str.isEmpty())
			return 0L;
		try {
			if (str.startsWith("0x"))
				return Long.parseLong(str.substring(2), 16);
			return Long.parseLong(str);
		} catch (Exception exception) {
			return -1L;
		}
	}
	
	protected void okPressed() {
		updateModel();
		super.okPressed();
	}
	
	private void updateModel() {
		model.setChip(chipCombo.getText());
		model.setImage(imageFileText.getText());
		model.setOffset(offsetText.getText());
		model.setType(flashTypeCombo.getText());
		
		model.setRemoteTarget(targetWidget.getSelectTarget());
		
		model.setHost(targetWidget.getSelectTarget().getHost());
		model.setPort(targetWidget.getSelectTarget().getPort());
		
		if (model.getRemoteTarget().isDefaultLocal()) {
			model.setPort(ProgramFlashModel.PORT);
		}
		
		model.setUseCustomizeFlash(useCustomizeFlash.getSelection());
		if (useCustomizeFlash.getSelection()) {
			model.setBankId(bankId.getText());
			model.setReadCmd(readCmd.getText());
			model.setPprogCmd(pprogCmd.getText());
			model.setEraseCmd(eraseCmd.getText());
			model.setPageSize(pageSize.getText());
			model.setSectorSize(sectorSize.getText());
			model.setChipSize(chipSize.getText());
		}

		model.setEnablePjtag(enablePjtagButton.getSelection());
		model.setEraseFlash(eraseFlashButton.getSelection());
		model.setEnableXip(enableXipButton.getSelection());
		model.setVerify(verifyButton.getSelection());
	}
	
	public ProgramFlashModel getModel() {
		return model;
	}
}
